import $ from 'jquery';
import Module from './Module';

export default class Keystroke extends Module {
  _init() {
    this.editor = this._module;
    this._keystrokeHandlers = {};
    return this._initKeystrokeHandlers();
  }

  add(key, node, handler) {
    key = key.toLowerCase();
    key = this.editor.hotkeys.constructor.aliases[key] || key;
    if (!this._keystrokeHandlers[key]) {
      this._keystrokeHandlers[key] = {};
    }
    return this._keystrokeHandlers[key][node] = handler;
  }

  respondTo(e) {
    let base, key, ref, result;
    key = (ref = this.editor.hotkeys.constructor.keyNameMap[e.which]) != null ? ref.toLowerCase() : void 0;
    if (!key) return;
    
    if (key in this._keystrokeHandlers) {
      result = typeof (base = this._keystrokeHandlers[key])['*'] === "function" ? base['*'](e) : void 0;
      if (!result) {
        (this.editor.selection.startNodes() || []).each(((_this => (i, node) => {
          let handler;
          let ref1;
          if (node.nodeType !== Node.ELEMENT_NODE) {
            return;
          }
          handler = (ref1 = _this._keystrokeHandlers[key]) != null ? ref1[node.tagName.toLowerCase()] : void 0;
          result = typeof handler === "function" ? handler(e, $(node)) : void 0;
          if (result === true || result === false) {
            return false;
          }
        }))(this));
      }
      if (result) {
        return true;
      }
    }
  }

  _initKeystrokeHandlers() {
    let titleEnterHandler;
    if (this.editor.util.browser.safari) {
      this.add('enter', '*', ((_this => e => {
        let $blockEl;
        let $br;
        if (!e.shiftKey) {
          return;
        }
        $blockEl = _this.editor.selection.blockNodes().last();
        if ($blockEl.is('pre')) {
          return;
        }
        $br = $('<br/>');
        if (_this.editor.selection.rangeAtEndOf($blockEl)) {
          _this.editor.selection.insertNode($br);
          _this.editor.selection.insertNode($('<br/>'));
          _this.editor.selection.setRangeBefore($br);
        } else {
          _this.editor.selection.insertNode($br);
        }
        return true;
      }))(this));
    }
    if (this.editor.util.browser.webkit || this.editor.util.browser.msie) {
      titleEnterHandler = ((_this => (e, $node) => {
        let $p;
        if (!_this.editor.selection.rangeAtEndOf($node)) {
          return;
        }
        $p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node);
        _this.editor.selection.setRangeAtStartOf($p);
        return true;
      }))(this);
      this.add('enter', 'h1', titleEnterHandler);
      this.add('enter', 'h2', titleEnterHandler);
      this.add('enter', 'h3', titleEnterHandler);
      this.add('enter', 'h4', titleEnterHandler);
      this.add('enter', 'h5', titleEnterHandler);
      this.add('enter', 'h6', titleEnterHandler);
    }
    this.add('backspace', '*', ((_this => e => {
      let $blockEl;
      let $prevBlockEl;
      let $rootBlock;
      let isWebkit;
      $rootBlock = _this.editor.selection.rootNodes().first();
      $prevBlockEl = $rootBlock.prev();
      if ($prevBlockEl.is('hr') && _this.editor.selection.rangeAtStartOf($rootBlock)) {
        _this.editor.selection.save();
        $prevBlockEl.remove();
        _this.editor.selection.restore();
        return true;
      }
      $blockEl = _this.editor.selection.blockNodes().last();
      isWebkit = _this.editor.util.browser.webkit;
      if (isWebkit && _this.editor.selection.rangeAtStartOf($blockEl)) {
        _this.editor.selection.save();
        _this.editor.formatter.cleanNode($blockEl, true);
        _this.editor.selection.restore();
        return null;
      }
    }))(this));
    this.add('enter', 'li', ((_this => (e, $node) => {
      let $cloneNode;
      let listEl;
      let newBlockEl;
      let newListEl;
      $cloneNode = $node.clone();
      $cloneNode.find('ul, ol').remove();
      if (!(_this.editor.util.isEmptyNode($cloneNode) && $node.is(_this.editor.selection.blockNodes().last()))) {
        return;
      }
      listEl = $node.parent();
      if ($node.next('li').length > 0) {
        if (!_this.editor.util.isEmptyNode($node)) {
          return;
        }
        if (listEl.parent('li').length > 0) {
          newBlockEl = $('<li/>').append(_this.editor.util.phBr).insertAfter(listEl.parent('li'));
          newListEl = $(`<${listEl[0].tagName}/>`).append($node.nextAll('li'));
          newBlockEl.append(newListEl);
        } else {
          newBlockEl = $('<p/>').append(_this.editor.util.phBr).insertAfter(listEl);
          newListEl = $(`<${listEl[0].tagName}/>`).append($node.nextAll('li'));
          newBlockEl.after(newListEl);
        }
      } else {
        if (listEl.parent('li').length > 0) {
          newBlockEl = $('<li/>').insertAfter(listEl.parent('li'));
          if ($node.contents().length > 0) {
            newBlockEl.append($node.contents());
          } else {
            newBlockEl.append(_this.editor.util.phBr);
          }
        } else {
          newBlockEl = $('<p/>').append(_this.editor.util.phBr).insertAfter(listEl);
          if ($node.children('ul, ol').length > 0) {
            newBlockEl.after($node.children('ul, ol'));
          }
        }
      }
      if ($node.prev('li').length) {
        $node.remove();
      } else {
        listEl.remove();
      }
      _this.editor.selection.setRangeAtStartOf(newBlockEl);
      return true;
    }))(this));
    this.add('enter', 'pre', ((_this => (e, $node) => {
      let $p;
      let breakNode;
      let range;
      e.preventDefault();
      if (e.shiftKey) {
        $p = $('<p/>').append(_this.editor.util.phBr).insertAfter($node);
        _this.editor.selection.setRangeAtStartOf($p);
        return true;
      }
      range = _this.editor.selection.range();
      breakNode = null;
      range.deleteContents();
      if (!_this.editor.util.browser.msie && _this.editor.selection.rangeAtEndOf($node)) {
        breakNode = document.createTextNode('\n\n');
        range.insertNode(breakNode);
        range.setEnd(breakNode, 1);
      } else {
        breakNode = document.createTextNode('\n');
        range.insertNode(breakNode);
        range.setStartAfter(breakNode);
      }
      range.collapse(false);
      _this.editor.selection.range(range);
      return true;
    }))(this));
    this.add('enter', 'blockquote', ((_this => (e, $node) => {
      let $closestBlock;
      let range;
      $closestBlock = _this.editor.selection.blockNodes().last();
      if (!($closestBlock.is('p') && !$closestBlock.next().length && _this.editor.util.isEmptyNode($closestBlock))) {
        return;
      }
      $node.after($closestBlock);
      range = document.createRange();
      _this.editor.selection.setRangeAtStartOf($closestBlock, range);
      return true;
    }))(this));
    this.add('backspace', 'li', ((_this => (e, $node) => {
      let $br;
      let $childList;
      let $newLi;
      let $prevChildList;
      let $prevNode;
      let $textNode;
      let isFF;
      let range;
      let text;
      $childList = $node.children('ul, ol');
      $prevNode = $node.prev('li');
      if (!($childList.length > 0 && $prevNode.length > 0)) {
        return false;
      }
      text = '';
      $textNode = null;
      $node.contents().each((i, n) => {
        if (n.nodeType === 1 && /UL|OL/.test(n.nodeName)) {
          return false;
        }
        if (n.nodeType === 1 && /BR/.test(n.nodeName)) {
          return;
        }
        if (n.nodeType === 3 && n.nodeValue) {
          text += n.nodeValue;
        } else if (n.nodeType === 1) {
          text += $(n).text();
        }
        return $textNode = $(n);
      });
      isFF = _this.editor.util.browser.firefox && !$textNode.next('br').length;
      if ($textNode && text.length === 1 && isFF) {
        $br = $(_this.editor.util.phBr).insertAfter($textNode);
        $textNode.remove();
        _this.editor.selection.setRangeBefore($br);
        return true;
      } else if (text.length > 0) {
        return false;
      }
      range = document.createRange();
      $prevChildList = $prevNode.children('ul, ol');
      if ($prevChildList.length > 0) {
        $newLi = $('<li/>').append(_this.editor.util.phBr).appendTo($prevChildList);
        $prevChildList.append($childList.children('li'));
        $node.remove();
        _this.editor.selection.setRangeAtEndOf($newLi, range);
      } else {
        _this.editor.selection.setRangeAtEndOf($prevNode, range);
        $prevNode.append($childList);
        $node.remove();
        _this.editor.selection.range(range);
      }
      return true;
    }))(this));
    this.add('backspace', 'pre', ((_this => (e, $node) => {
      let $newNode;
      let codeStr;
      let range;
      if (!_this.editor.selection.rangeAtStartOf($node)) {
        return;
      }
      codeStr = $node.html().replace('\n', '<br/>') || _this.editor.util.phBr;
      $newNode = $('<p/>').append(codeStr).insertAfter($node);
      $node.remove();
      range = document.createRange();
      _this.editor.selection.setRangeAtStartOf($newNode, range);
      return true;
    }))(this));
    return this.add('backspace', 'blockquote', ((_this => (e, $node) => {
      let $firstChild;
      let range;
      if (!_this.editor.selection.rangeAtStartOf($node)) {
        return;
      }
      $firstChild = $node.children().first().unwrap();
      range = document.createRange();
      _this.editor.selection.setRangeAtStartOf($firstChild, range);
      return true;
    }))(this));
  }
}

Keystroke.pluginName = 'Keystroke';